/*
 *
 */

#include "common/sketchbook.hpp"

struct vein
{
	std::vector<float2> path = {};
	float2 velocity = {};
	float width = 0.f;
};

std::vector<vein> veins;
constexpr auto radius = 0.4f;
constexpr auto center = float2::one(0.5f);

void bloodshoot()
{
	std::cout << "seed: " << std::hex << std::showbase << tiny_rand << '\n';

	veins.resize(0);

	const auto bursts = trand_int({1, 4});
	std::generate_n(std::back_inserter(veins), bursts, []()
	{
		const auto start_point = common::rotate(float2::j(radius), common::protractor<>::tau(trand_float())) + center;
		return vein
		{
			.path = {start_point},
			.velocity = (center - start_point)/25,
			.width = 1/50.f
		};
	});

	auto current_veins = range{support::offset_expander(veins), support::offset_expander(veins, veins.end())};
	for(int i = 8; i --> 0;)
	{
		for(vein& vein : current_veins)
		{
			for(int i = 4; i --> 0;)
			{
				const auto velocity = common::rotate(vein.velocity,
					common::protractor<>::tau(
						support::wrap(trand_float({-1/8.f, 1/8.f}), 1.f)
					)
				);

				vein.path.push_back(vein.path.back() + velocity);

				if((vein.path.back() - center).quadrance() > radius*radius)
				{
					auto tangent = common::rotate(center - vein.path.back(),
						common::protractor<>::tau(1/4.f));
					vein.path.back() -= velocity;
					vein.velocity = common::reflect(velocity, tangent);
					vein.path.back() += vein.velocity;
				}
			}
		}

		auto new_veins_end = current_veins.end();

		for(vein& v : current_veins)
		{
			auto split = trand_int({1,3});
			const auto step = 1/2.f / split;
			auto angle_range = range{-1/4.f, -1/4.f + step};
			new_veins_end = std::generate_n(new_veins_end, split,
			[
				root = v.path.back(),
				velocity = v.velocity,
				width = v.width * 0.7f,
				&angle_range, &step
			]()
			{
				auto v = vein
				{
					.path = {root},
					.velocity = common::rotate(velocity,
						common::protractor<>::tau(
							support::wrap(trand_float(angle_range), 1.f)
						)
					),
					.width = width
				};
				angle_range += step;
				return v;
			});
		}
		current_veins.lower() = current_veins.end();
		current_veins.upper() = new_veins_end;

	}


	std::cout << "vertex count: " << std::dec <<
		std::accumulate(veins.begin(), veins.end(), 0,
			[](auto r, const auto& v) { return r + v.path.size(); })
	<< '\n';
}

void start(Program& program)
{
	program.resizable = true;
	program.key_up = [&](scancode code, keycode)
	{
		switch(code)
		{
			case scancode::leftbracket:
			case scancode::c:
				if(pressed(scancode::rctrl) || pressed(scancode::lctrl))
			case scancode::escape:
				program.end();
			break;

			case scancode::space:
				bloodshoot();
			break;

			default: break;
		}
	};

	if(program.argc > 2)
	{
		using support::ston;
		using seed_t = decltype(tiny_rand());
		tiny_rand.seed({ ston<seed_t>(program.argv[1]), ston<seed_t>(program.argv[2]) });
	}

	bloodshoot();

	program.draw_loop = [&](auto frame, auto)
	{
		frame.begin_sketch()
			.rectangle(rect{frame.size})
			.fill(rgb::white(0.5))
		;

		frame.begin_sketch()
			.ellipse(rect{frame.size * radius * 2, center*frame.size, float2::one(0.5f)})
			.fill(rgb::white())
		;

		for(auto&& vein : veins)
		{
			auto sketch = frame.begin_sketch();
			sketch.move(vein.path.front() * frame.size);
			for(auto&& x : range{vein.path.begin()+1, vein.path.end()})
			{
				sketch.vertex(x * frame.size);
			}
			sketch
				.line_width(min_element(frame.size * vein.width))
				.line_cap(sketch::cap::round)
				.line_join(sketch::join::round)
				.outline(rgb::red())
			;
		}
	};
}
